package com.electric.flinkcep.model;

import java.io.Serializable;
import java.util.Objects;

/**
 * 电力负荷预测事件模型
 * 用于存储匹配的真实数据和预测数据，进行误差分析
 */
public class LoadPredictionEvent implements Serializable {
    
    private TrueData trueData;
    private PredictData predictData;
    private double absoluteError;  // 绝对误差
    private double squaredError;   // 平方误差
    private long eventTime;        // 事件时间戳
    
    // 默认构造函数
    public LoadPredictionEvent() {
    }
    
    // 构造函数
    public LoadPredictionEvent(TrueData trueData, PredictData predictData) {
        this.trueData = trueData;
        this.predictData = predictData;
        this.eventTime = trueData.getTimestampMillis();
        calculateErrors();
    }
    
    /**
     * 计算误差指标
     */
    private void calculateErrors() {
        if (trueData != null && predictData != null) {
            this.absoluteError = Math.abs(trueData.getLoad() - predictData.getPredictedLoad());
            this.squaredError = Math.pow(trueData.getLoad() - predictData.getPredictedLoad(), 2);
        }
    }
    
    /**
     * 判断误差是否较大
     * 使用相对误差阈值：如果绝对误差超过真实值的20%，则认为误差较大
     */
    public boolean isLargeError() {
        if (trueData == null || predictData == null) {
            return false;
        }
        
        double trueLoad = trueData.getLoad();
        if (trueLoad == 0) {
            return absoluteError > 100; // 如果真实值为0，使用绝对阈值
        }
        
        double relativeError = absoluteError / Math.abs(trueLoad);
        return relativeError > 0.2; // 20%的相对误差阈值
    }
    
    /**
     * 获取相对误差百分比
     */
    public double getRelativeErrorPercentage() {
        if (trueData == null || predictData == null || trueData.getLoad() == 0) {
            return 0.0;
        }
        return (absoluteError / Math.abs(trueData.getLoad())) * 100;
    }
    
    // Getter和Setter方法
    public TrueData getTrueData() {
        return trueData;
    }
    
    public void setTrueData(TrueData trueData) {
        this.trueData = trueData;
        if (this.predictData != null) {
            calculateErrors();
        }
    }
    
    public PredictData getPredictData() {
        return predictData;
    }
    
    public void setPredictData(PredictData predictData) {
        this.predictData = predictData;
        if (this.trueData != null) {
            calculateErrors();
        }
    }
    
    public double getAbsoluteError() {
        return absoluteError;
    }
    
    public double getSquaredError() {
        return squaredError;
    }
    
    public long getEventTime() {
        return eventTime;
    }
    
    public void setEventTime(long eventTime) {
        this.eventTime = eventTime;
    }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        LoadPredictionEvent that = (LoadPredictionEvent) o;
        return eventTime == that.eventTime &&
               Objects.equals(trueData, that.trueData) &&
               Objects.equals(predictData, that.predictData);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(trueData, predictData, eventTime);
    }
    
    @Override
    public String toString() {
        return "LoadPredictionEvent{" +
                "trueLoad=" + (trueData != null ? trueData.getLoad() : "null") +
                ", predictedLoad=" + (predictData != null ? predictData.getPredictedLoad() : "null") +
                ", absoluteError=" + absoluteError +
                ", relativeError=" + String.format("%.2f%%", getRelativeErrorPercentage()) +
                ", isLargeError=" + isLargeError() +
                ", eventTime=" + eventTime +
                '}';
    }
}